package com.tzy.tzyrpccore.provider;

import com.tzy.tzyrpccore.annotation.TzyRpcAnnotation;
import com.tzy.tzyrpccore.api.RpcRequest;
import com.tzy.tzyrpccore.api.RpcResponse;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * @author caituxinchu
 */
// Spring生命周期注入
public class ProviderBootStrap implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    private Map<String, Object> serviceMap = new HashMap<>();

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    // 对象创建完毕，还没有初始化，获取到所有服务提供者
    @PostConstruct
    public void buildProviders() {
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(TzyRpcAnnotation.class);
        for (Map.Entry<String, Object> entry : beansWithAnnotation.entrySet()) {
            Class<?>[] interfaces = entry.getValue().getClass().getInterfaces();
            for (Class<?> anInterface : interfaces) {
                serviceMap.put(anInterface.getName(), entry.getValue());
            }
        }
    }

    public RpcResponse invokeMethod(RpcRequest rpcRequest) {
        RpcResponse result = new RpcResponse();
        try {
            String serviceName = rpcRequest.getServiceName();
            Object providerObj = serviceMap.get(serviceName);
            Method method = findMethod(providerObj, rpcRequest.getMethodName());
            Object data = method.invoke(providerObj, rpcRequest.getArgs());
            result.setData(data);
            result.setStatus(true);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            result.setStatus(false);
            result.setData(null);
            return result;
        }
    }

    private Method findMethod(Object providerObj, String methodName) {
        Method[] methods = providerObj.getClass().getMethods();
        return Arrays.stream(methods).filter(method -> method.getName().equals(methodName)).findFirst().orElse(null);
    }
}
